package com.hontech.desktoppastacooker.conn.frame

import com.hontech.bv.conn.serial.Uint16
import com.hontech.desktoppastacooker.conn.ErrCode
import com.hontech.desktoppastacooker.conn.serial.SerialType
import com.hontech.desktoppastacooker.conn.serial.Uint8

data class Frame(val type: Int, val data: ByteArray) {

    companion object {

        const val TYPE_ACK = 0
        const val TYPE_PING = 1
        const val TYPE_PONG = 2
        const val TYPE_SESSION = 3
        const val TYPE_REQ = 4
        const val TYPE_RES = 5
        const val TYPE_QUERY = 6
        const val TYPE_RESULT = 7
        const val TYPE_NOTIFY = 8
        const val TYPE_NOTIFY_ACK = 9
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as Frame

        if (type != other.type) return false
        if (!data.contentEquals(other.data)) return false

        return true
    }

    override fun hashCode(): Int {
        var result = type
        result = 31 * result + data.contentHashCode()
        return result
    }
}

data class NotifyFrame(val cmd: Int, val data: ByteArray) {

    // type cmd ...
    fun parse(args: Array<SerialType>) {
        var index = 2
        for (arg in args) {
            arg.decode(data, index)
            index += arg.size()
        }
    }

    fun u8(): Int {
        val value = Uint8()
        parse(arrayOf(value))
        return value.value
    }

    fun u16(): Int {
        val value = Uint16()
        parse(arrayOf(value))
        return value.value
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as NotifyFrame

        if (cmd != other.cmd) return false
        if (!data.contentEquals(other.data)) return false

        return true
    }

    override fun hashCode(): Int {
        var result = cmd
        result = 31 * result + data.contentHashCode()
        return result
    }
}

typealias ResultFrame = NotifyFrame


data class ResFrame(val seq: Int, val cmd: Int, val data: ByteArray) {

    // type seq cmd

    fun parse(args: Array<SerialType>) {
        var index = 3
        for (arg in args) {
            arg.decode(data, index)
            index += arg.size()
        }
    }


    fun assertErr() {
        val ec = Uint8()
        parse(arrayOf(ec))
        if (ec.value != 0) {
            throw IllegalStateException(ErrCode.msg(ec.value))
        }
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as ResFrame

        if (seq != other.seq) return false
        if (cmd != other.cmd) return false
        if (!data.contentEquals(other.data)) return false

        return true
    }

    override fun hashCode(): Int {
        var result = seq
        result = 31 * result + cmd
        result = 31 * result + data.contentHashCode()
        return result
    }
}


